package org.ntu.rtsearch.index;

import java.util.HashMap;
import java.util.Map;

import org.ntu.rtsearch.index.model.Document;
import org.ntu.rtsearch.index.model.InvertedIndex;


public class MutiIndexWriter extends IndexWriter{
	
	private static final int K = 3;
	
	private static final int MAX_SIZE = 10000;	// max amount of posting the first index contains

	private SingleIndexWriter indexWriter = new SingleIndexWriter();
	
	private long sizeInByte = 0;
		
	// hold for all indexes
	private Map<Integer, InvertedIndex> indexMap = new HashMap<Integer, InvertedIndex>();
	
		
	@Override
	public void addDocument(Document doc) throws Exception {
		indexWriter.addDocument(doc);
		maybeMerge();
	}

	/**
	 * merge if the first index size reach the threshold
	 */
	private void maybeMerge() {
		if(indexWriter.getIndexSize() > MAX_SIZE) {
			InvertedIndex toMerge = indexWriter.getIndex();
			System.out.println("merge");
			for (int i = 1;; i++) {
				InvertedIndex index = indexMap.get(i); 
				if(index != null) {
					sizeInByte -= index.getSizeInByte();
					toMerge = index.mergeWith(toMerge);
					
					sizeInByte += toMerge.getSizeInByte();					
					// remove the old index out of the index set
					indexMap.remove(i);					
				} else {
					indexMap.put(i, toMerge);
					break;
				} 
				
				// refresh index i
				if(toMerge.getSize() < power(K, i) * MAX_SIZE) {
					indexMap.put(i, toMerge);
					break;
				} 
			}
			
			postingCount += indexWriter.getIndexSize();
			indexWriter.setIndex(new InvertedIndex());
			showAllIndex();
		}
	}
	
	/**
	 * show all the index
	 */
	public void showAllIndex() {
		System.out.println("show all the indexes' size: ");
		System.out.println("0 : " + indexWriter.postingCount);
		for (Map.Entry<Integer, InvertedIndex> entry : indexMap.entrySet()) {
			System.out.println(entry.getKey() + " : " + entry.getValue().getSize());
		}
	}
	
	public int power(int base, int power) {
		int result = 1;
		for(int i = 0; i < power; i++) {
			result *= base;
		}
		return result;
	}

	@Override
	/**
	 * return the sum of all Indexes' posting amount
	 */
	public long getIndexSize() {
		return postingCount + indexWriter.getIndexSize();
	}
	
	public long getSizeInByte() {
		return sizeInByte + indexWriter.getSizeInByte();
	}

	public SingleIndexWriter getIndexWriter() {
		return indexWriter;
	}

	public Map<Integer, InvertedIndex> getIndexMap() {
		return indexMap;
	}
	
	
}
